/* File: ast_decl.h
 * ----------------
 * In our parse tree, Decl nodes are used to represent and
 * manage declarations. There are 4 subclasses of the base class,
 * specialized for declarations of variables, functions, classes,
 * and interfaces.
 *
 * pp4: You will need to extend the Decl classes to implement 
 * code generation for declarations.
 */

#ifndef _H_ast_decl
#define _H_ast_decl

#include "ast.h"
#include "list.h"
#include "codegen.h"

class Type;
class NamedType;
class Identifier;
class Stmt;
class Location;
class FnDecl;

class Decl : public Node 
{
  protected:
    Identifier *id;
  
  public:
    Decl(Identifier *name);
    friend ostream& operator<<(ostream& out, Decl *d) { return out << d->id; }
		
		//identifier name info
    const char* getName(){return this->id->getName();}
		
		//scope info
		virtual void useScope() {}
				//memory info
    virtual int getSpace() {return 0;}
		virtual int getVSpace() = 0;
		
		//location info
		virtual void locationSet() = 0;
		virtual Location* codeGen(CodeGenerator *cg) = 0;
		
		//store info
		virtual void addNamePrefix(const char *str) = 0;
		
};

class VarDecl : public Decl 
{
  protected:
    int offset;
    Location *l;
    Type *type;
    
  public:
    VarDecl(Identifier *name, Type *type);
		
		//type info
		Type* getType() {
			return type;
		}
		
		//codeGen info
		Location* codeGen(CodeGenerator *cg) { return NULL; }
		void locationSet() {}
		
		//location info
    void setLocation(Location *loc) { l = loc; }
		Location* getLocation() {
			return l;
		}
		void setOffset(int o) {
			offset = o;
		}
		int getOffset() {
			return offset;
		}
		
		//memory info
		int getSpace();
		int getVSpace() {
			return 0;
		}
		
		//scope
		void useScope() { }
		
		//info
		void addNamePrefix(const char *str) { }
};

class ClassDecl : public Decl 
{
  protected:
    List<Decl*> *members;
    NamedType *extends;
    List<NamedType*> *implements;

  public:
    ClassDecl(Identifier *name, NamedType *extends,
		    List<NamedType*> *implements, List<Decl*> *members);
		
		//type info
		NamedType* getType();
		NamedType* getExtends() {
			return extends;
		}
		
		//scope & gen
		Location* codeGen(CodeGenerator *cg);
		void locationSet();
		void useScope();
		
		//memory info
		int getSpace();
		int getVSpace();
		
		void addNamePrefix(const char *str) {}
		List<FnDecl*>* getDecls();
		
};

class InterfaceDecl : public Decl 
{
  protected:
    List<Decl*> *members;
    
  public:
    InterfaceDecl(Identifier *name, List<Decl*> *members);
		//location
		void locationSet() {}
		Location* codeGen(CodeGenerator *cg) {
			return NULL;
		}
		
		//memory & scope
		void useScope();
		int getSpace() {
			return 0;
		}
		int getVSpace() {
			return 0;
		}
		
		//naming
		void addNamePrefix(const char *str) {}
};

class FnDecl : public Decl 
{
  protected:
    List<VarDecl*> *formals;
    Type *returnType;
    Stmt *body;
		std::string *label;
		int offset;
		bool checkMethod;
    
  public:
    FnDecl(Identifier *name, Type *returnType, List<VarDecl*> *formals);
    void SetFunctionBody(Stmt *b);
		
		//typing & naming info
		Type* getType() {
			return returnType;
		}
		const char* getLabel();
		void addNamePrefix(const char *str);
		bool checkReturn();
		
		//check if method
		void setCheck(bool x) {
			checkMethod = x;
		}
		
		//memory
		int getSpace() {
			return CodeGenerator::VarSize;
		}
		int getVSpace();
                int getVOffset() { return offset; }
                void setVOffset(int v) { offset = v; }
		
		//scope
		void useScope();
		void locationSet() {}
		Location* codeGen(CodeGenerator *cg);
};

#endif
